package com.ssis.core;

import java.util.Random;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import com.ssis.graphics.Dialog;
import com.ssis.graphics.Renderer;
import com.ssis.graphics.Text;
import com.ssis.graphics.Textures;

/**
 * Basic game
 *
 * @author Steve Wohlwend <theothersteve7@gmail.com>
 * @version 0.03
 */
public class Game {
	
	/** Game title */
	public static final String GAME_TITLE = "Space Stations in Space";
	
	/** Desired frame time */
	private static final int FRAMERATE = 60;
	
	/** Exit the game */
	private static boolean finished;
	
	private Random random;
	public static final int WIDTH = 800;
	public static final int HEIGHT = 600;
	Renderer renderer;
	private Station station;
	private HUDStation hudStation;
	private HUDCrew hudCrew;
	private Text text;
	private InputHandler input;
	private boolean[] mouseButtonHeld;
	
	public state_types state;
	public static enum state_types {
		MAIN_MENU,
		STATION,
		DIALOG,
		CREW_MENU
	}
	
	
	/**
	 * Application init
	 * @param args Commandline args
	 */
	public static void main(String[] args) {
		Game game = new Game();
		
		try {
			game.init();
			game.run();
		} catch (Exception e) {
			e.printStackTrace(System.err);
			Sys.alert(GAME_TITLE, "An error occured and the game will exit.");
		} finally {
			game.cleanup();
		}
		System.exit(0);
	}
	
	/**
	 * Initialize the game
	 * @throws Exception if init fails
	 */
	private void init() throws Exception {
		// Create a window with 1:1 orthographic 2D projection
		Display.setTitle(GAME_TITLE);
	
		// Enable vsync if we can (due to how OpenGL works, it cannot be guaranteed to always work)
		Display.setVSyncEnabled(true);
	
		// Create default display
		Display.setDisplayMode(new DisplayMode(WIDTH,HEIGHT));
		Display.create();
		
		Textures.initialize();
		random = new Random();
		state = state_types.MAIN_MENU;

		CrewNameGenerator.init(random);
		this.station = new Station();
		this.hudStation = new HUDStation(station);
		this.hudCrew = new HUDCrew(this);
		this.text = new Text();
		Dialog.init(this);
		Dialog.setConversation(0);
		
		renderer = new Renderer(this);
		input = new InputHandler(this);
		mouseButtonHeld = new boolean[Mouse.getButtonCount()];
		for(int i=0; i<Mouse.getButtonCount(); i++) {
			mouseButtonHeld[i] = false;
		}
	}
	
	/**
	 * Runs the game (the "main loop")
	 */
	private void run() {
	
		while (!finished) {
			// Always call Window.update(), all the time - it does some behind the
			// scenes work, and also displays the rendered output
			Display.update();
		
			// Check for close requests
			if (Display.isCloseRequested()) {
				finished = true;
			} 
		
			// The window is in the foreground, so we should play the game
			else if (Display.isActive()) {
				logic();
				renderer.render();
				Display.sync(FRAMERATE);
			} 
		
			// The window is not in the foreground, so we can allow other stuff to run and
			// infrequently update
			else {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// do nothing
				}
				logic();
		
				// Only bother rendering if the window is visible or dirty
				if (Display.isVisible() || Display.isDirty()) {
					renderer.render();
				}
			}
		}
	}
	
	/**
	 * Do any game-specific cleanup
	 */
	private void cleanup() {
		// Close the window
		Display.destroy();
	}
	
	/**
	 * Do all calculations, handle input, etc.
	 */
	private void logic() {
		int x = Mouse.getX();
		int y = Display.getHeight() - Mouse.getY();
		
		// esc exits
		if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
			finished = true;
		}
		for(int i=0; i<Mouse.getButtonCount(); i++) {
			if(Mouse.isButtonDown(i)) {
				input.inputClick(i, x, y, mouseButtonHeld[i]);
				mouseButtonHeld[i] = true;
			} else {
				mouseButtonHeld[i] = false;
			}
		}
	}
	
	public Station station() {
		return this.station;
	}
	
	public Random rand() {
		return random;
	}

	public HUDStation hudStation() {
		return hudStation;
	}
	
	public HUDCrew hudCrew() {
		return hudCrew;
	}
	
	public Text text() {
		return text;
	}
}